<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>opencv 抠除指定区域</title>
    <!-- <script src='https://docs.opencv.org/版本号/opencv.js'></script> -->
    <!-- OpenCV.js 4.5.5 版本 -->
    <!-- <script src='https://docs.opencv.org/4.5.5/opencv.js'></script> -->

    <!-- <script src='./opencv_4.5.5.js' type="module"></script> -->

    <!-- You may want to load opencv.js asynchronously by async attribute in <script> tag. To be notified when opencv.js is ready, you can register a callback to onload attribute. -->
    <script src="./9_def_rune_tool_2/common/utils/my_opencv_fun.js"></script>
    <script async src="./opencv_4.5.5.js" onload="openCvReady()" type="text/javascript"></script>



    <canvas style="display: none;" id="img3" width="70" height="70"></canvas>
    <canvas id="imageCanvasInput" width="400" height="400"></canvas>
    <canvas id="canvasOutput" width="400" height="400"></canvas>
    <hr />
    <!-- <canvas id="templateCanvasInput" width="70" height="70"></canvas> -->


    <canvas id="Image" width="400" height="400"></canvas>
    <!-- <canvas id="Mask" width="400" height="400"></canvas> -->
    <canvas id="Image2" width="400" height="400"></canvas>
    <canvas id="Result" width="400" height="400"></canvas>

</head>

<body style="background-color: #260853;">
    <!-- <script type="module">
        import * as cv from './opencv_4.5.5.js';
        console.log(cv);
    </script> -->
    <script>
        // console.log("xxx", window.$mocvf);
        async function openCvReady() {
            // 脚本加载完成
            // console.log(cv);
            // opencv.js 在真正初始化之前加载并触发 onload 事件。为了等到 opencv.js 真正准备好，opencv.js 提供了一个挂机“onRuntimeInitialized”。像这样使用它：

            // var img1 = new Image();
            // img.crossOrigin = 'anonymous';
            // img1.src = './img1.png';
            // console.log(1);

            // var src1 = "./img1.png";
            // var src2 = "./img2.png";

            // var src1 = "./icons.png";
            var src1 = "./bag_rune.jpg";
            // var src2 = "./icon.png";
            var src2 = "./img3.png";
            await Promise.all([await loadImg(src1).then(img1 => {
                // console.log(img1);
                var canvas1 = document.getElementById('imageCanvasInput');
                var ctx1 = canvas1.getContext('2d');
                // img1.onload = function () {
                //     ctx1.drawImage(img1, 0, 0);
                // }
                canvas1.width = img1.width;
                canvas1.height = img1.height;
                ctx1.drawImage(img1, 0, 0);


                var canvas3 = document.getElementById('canvasOutput');
                canvas3.width = img1.width;
                canvas3.height = img1.height;
                var ctx3 = canvas3.getContext('2d');
                ctx3.drawImage(img1, 0, 0);

                // console.log(12);
            }), await loadImg(src2).then(img2 => {
                // console.log(img2);
                var canvas2 = document.getElementById('img3');
                canvas2.width = img2.width;
                canvas2.height = img2.height;
                var ctx2 = canvas2.getContext('2d');
                ctx2.drawImage(img2, 0, 0);
                // console.log(13);
            })]);

            // console.log(2);
            cv['onRuntimeInitialized'] = () => {
                console.log("xxx");
                // cv.imshow('imageCanvasInput', drawSrc);
                // 读取原始图像
                let image = cv.imread("imageCanvasInput");

                // 创建与原始图像大小相同的空白掩膜图像
                // numpy.zeros_like(image);
                // 定义要扣出的特定区域（矩形示例）

                /**
                let img2 = cv.Mat.zeros(image.cols, image.rows, image.type());

                // console.log(cv, img2);
                let x = 10;
                let y = 10;
                let w = 30;
                let h = 30;
                // 在掩膜图像上绘制矩形
                cv.rectangle(img2, new cv.Point(x, y), new cv.Point(x + w, y + h), new cv.Scalar(123, 123, 123,
                    255), -1, cv.LINE_8, 0);

                // 将掩膜图像与原始图像进行按位与操作
                let result = img2.clone();

                cv.subtract(image, img2, result);
                // cv.bitwise_and(image, img2, result);

                */




                // 数字与等级
                let arr_l = [225, 0, 0, 255];
                let arr_h = [255, 255, 255, 255];
                // 符石
                // let arr_l = [140, 140, 140, 255];
                // let arr_h = [200, 200, 200, 255];

                // cv.inRange 方法原理
                /*
                let img_t = image.clone();

                let rows = img_t.rows;
                cols = img_t.cols * img_t.channels();
                let img_point, temp_point; //像素类型uchar
                console.log("通道数:", img_t.channels());
                for (let i = 0; i < rows; i++) //遍历图像像素
                {
                    img_point = img_t.ucharPtr(i);
                    for (let j = 0; j < cols;) {

                        let j_ = j;
                        let r = img_point[j];
                        let g = img_point[j + 1];
                        let b = img_point[j + 2];
                        let a = img_point[j + 3];
                        
                        j += 4;

                        if (r > (arr_l[0] - 1) && r < (arr_h[0] + 1)) {
                            if (g > (arr_l[1] - 1) && g < (arr_h[1] + 1)) {
                                if (b > (arr_l[2] - 1) && b < (arr_h[2] + 1)) {
                                    img_point[j_] = 255;
                                    img_point[j_ + 1] = 255;
                                    img_point[j_ + 2] = 255;
                                    img_point[j_ + 3] = 255;
                                    // 该区域替换成白色
                                    // console.log(`rgba(${r},${g},${b},${a})`);
                                    continue;
                                }
                            }
                        }

                        // 其他区域替换成透明
                        img_point[j_] = 0;
                        img_point[j_ + 1] = 0;
                        img_point[j_ + 2] = 0;
                        img_point[j_ + 3] = 0;


                    }
                }

                cv.imshow("imageCanvasInput", img_t);

                */

                let img2_b_w = image.clone();
                let low_hsv_src = new cv.Mat(img2_b_w.rows, img2_b_w.cols, img2_b_w.type(), arr_l);
                let high_hsv_src = new cv.Mat(img2_b_w.rows, img2_b_w.cols, img2_b_w.type(), arr_h);
                cv.inRange(img2_b_w, low_hsv_src, high_hsv_src, img2_b_w);
                // console.log("inRange处理后通道数",img2.channels());// 1
                cv.imshow("Image2", img2_b_w);
                img2 = cv.imread("Image2"); // cv.CV_8U转化成 cv.CV_8UC4

                let mask = cv.Mat.zeros(image.cols, image.rows, image.type());
                // cv.rectangle(img2, new cv.Point(0, 0), new cv.Point(mask.cols, mask.rows), new cv.Scalar(255, 255,255, 255), -1, cv.LINE_8, 0);

                // img2.copyTo(img2, mask);
                // let mask = cv.Mat.zeros(image.cols, image.rows, cv.CV_8UC3);
                // cv.imshow("Image2", mask);
                // mask = cv.imread("Image2");


                /**@todo 如何直接计算出黑白图中的白色，并将黑色替换成透明 减法？位与？
                 * 
                 * 去除黑色背景 https://blog.csdn.net/lhzhqq/article/details/135198371
                 * 无效
                 */

                /**
                let tmp = cv.imread("img3");
                // let tmp = img2.clone();
                let tmp_gray = new cv.Mat();
                cv.cvtColor(tmp, tmp_gray, cv.COLOR_BGR2GRAY); // 将图像背景转换为灰色图像背景。
                // cv.imshow("imageCanvasInput", tmp_gray);
                // return;
                
                // cv.threshold https://docs.opencv.org/4.5.5/d7/d1b/group__imgproc__misc.html#gae8a4a146d1ca78c626a53577199e9c57
                // Returns the computed threshold value if Otsu's or Triangle methods used.
                let alpha = cv.threshold(tmp_gray, tmp_gray, 0, 255, cv.THRESH_BINARY); // 应用阈值技术。
                // console.log("通道数:", tmp_gray.channels());
                let channels_ = new cv.MatVector();
                cv.split(tmp_gray, channels_);
                // console.log(channels_.get(0));

                // cv.imshow("imageCanvasInput", tmp_gray);
                // return;
                // let alpha = cv.threshold(tmp_gray, tmp_gray, 0, 255, cv.THRESH_OTSU); // 应用阈值技术。
                // let alpha = cv.threshold(tmp_gray, tmp_gray, 0, 255, cv.THRESH_TRIANGLE); // 应用阈值技术。
                // console.log(alpha); // 0

                // let channels = new Array(3).fill(new cv.Mat());
                // let channels = [new cv.Mat(),new cv.Mat(),new cv.Mat()];
                let channels = new cv.MatVector();
                // cv.split https://docs.opencv.org/4.5.5/d2/de8/group__core__array.html#ga0547c7fed86152d7e9d0096029c8518a
                cv.split(img2, channels); //分割彩色图像的通道。
                // console.log(channels);
                let r = channels.get(0);
                let g = channels.get(1);
                let b = channels.get(2);
                let a = channels.get(3);
                console.log(channels_.get(0).type());
                console.log(a.type());
                channels.set(3, channels_.get(0));// Uncaught (in promise) 6705472
                // console.log(r, b, g, a);
                // let rgba = [r, g, b, alpha];
                // cv.merge https://docs.opencv.org/4.5.5/d2/de8/group__core__array.html#ga7d7b4d6c6ee504b30a20b1680029c7b4
                // cv.merge(rgba, 4, tmp); 
                cv.merge(channels, tmp); // 使用 cv.merge() 将 rgba 合并为彩色/多通道图像。
                cv.imshow("imageCanvasInput", tmp);

                */

                // let img_t = cv.Mat.zeros(image.cols, image.rows, image.type());
                // cv.rectangle(img_t, new cv.Point(0, 0), new cv.Point(image.cols, image.rows), new cv.Scalar(0, 0, 2, 255), -1, cv.LINE_8, 0);

                let result = img2.clone();

                // cv.divide(img2, img_t, result);

                // cv.subtract(img2, image, result);
                // cv.subtract(img_t, img2, result);
                // cv.bitwise_and(img2, mask, result);

                /** @link https://blog.csdn.net/septwolves2015/article/details/97896681 
                 * @link https://blog.csdn.net/u011028345/article/details/77278467
                 */

                // cv.bitwise_not(img2, img2); // 反转二值图！！！要反转的是  cv.CV_8U, 不是 cv.CV_8UC4
                cv.bitwise_not(img2_b_w, img2_b_w); // 反转二值图
                cv.imshow("Image2", img2_b_w);

                // let img2gray = img2.clone();
                let img2gray = cv.imread("Image2").clone();

                cv.cvtColor(img2gray, img2gray, cv.COLOR_BGR2GRAY);
                /**
                 * @todo img2gray 白色转成透明
                 * 掩码只能是单通道的，下面操作只适用于接受白色或黑色背景的应用场景。目前解决办法只有上面的指针操作了。
                 */

                // 利用掩膜（mask）进行“与”操作，即掩膜图像白色区域是对需要处理图像像素的保留，黑色区域是对需要处理图像像素的剔除，其余按位操作原理类似只是效果不同而已。

                // cv.cvtColor(image, img2gray, cv.COLOR_BGR2GRAY);
                // cv.bitwise_xor(image, image, result, img2gray);// 剔除掩膜白色内容
            
                // optional operation mask, 8-bit single channel array, that specifies elements of the output array to be changed.

                // cv.bitwise_or(image, image, result, img2gray);
                cv.bitwise_and(image, image, result, img2gray); // 用掩膜位运算提取白色区域的内容。

                // cv.subtract(image, img2, result, img2gray);

                // 显示
                // cv.imshow("Image", mask);
                cv.imshow("Image", image);
                // cv.imshow("Image2", img2);
                cv.imshow("Result", result);



                // console.log(res);

            };




        }

        function loadImg(url) {
            return new Promise((resolve, reject) => {
                let img = new Image();
                // img.crossOrigin = ''; 
                // img.crossOrigin = 'anonymous';
                // 跨域 直接用live server运行 或者使用webview打开
                img.src = url;
                img.onload = () => {
                    resolve(img);
                };
                img.onerror = reject;
            });
        }
    </script>
</body>

</html>